#include "Thread.hpp"
#include "Mutex.hpp"
#include <unistd.h>
#include <memory>
#include <vector>
#include <cassert>
#include <mutex>

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; // 定义全局的锁，不需要调用pthread_mutex_init()进行初始化

class ThreadData
{
public:
    ThreadData(std::string name, pthread_mutex_t *lock)
        : _name(name), _lock(lock)
    {
    }
    ~ThreadData()
    {
    }

public:
    std::string _name;
    pthread_mutex_t *_lock;
};

// 1. 如何看待锁
//    a. 锁本身就是一个共享资源，他是用来保护全局资源的，那谁来保护锁呢？
//    b. 所以pthread_mutex_lock加锁的过程必须是安全的  --> 加锁的过程是原子的！
//    c. 如果申请锁成功，继续向后执行，如果申请暂时没有成功，执行流则阻塞
//    d. 谁持有锁，谁进入临界区

// 2. 加锁和解锁的本质 -- 加锁的过程是原子的！


// 函数是否为可重入函数取决于当多个执行流执行时会不会出问题，如果出问题了，就是不可重入函数，不出问题那就是可重入函数
// 线程是否安全取决于该函数内是否存在某些代码片段，当多个执行流去执行这个片段时，如果出现数据不一致问题，那就是线程不安全，反之就是线程安全的


// 死锁：我自己已经申请到了一把锁，对方也申请到了他的锁，但是我还是要对方锁，而且对方也要我的锁，就会造成死锁
// 多个执行流互相等待对方的资源造成代码无法推进执行


int tickets = 10000;

void *get_tickets(void *args)
{
    std::string name = static_cast<const char *>(args);
    // ThreadData *td = static_cast<ThreadData*>(args);
    while (true)
    {

        // 加锁和解锁的多个是让多个线程串行执行，所以程序变慢了
        // 锁只是规定互斥访问，没有规定谁必须优先执行(互斥：想让多个线程串行访问共享资源)
        // 锁的出现，就会出现多个线程竞争的局面

        // pthread_mutex_lock(&lock);

        // 如果持有锁，然后再去申请锁，那么就会出错了
        // int n = pthread_mutex_trylock(&lock);
        // assert(0 == n);
        // (void)n;

        {
            lockGuard lockguard(&lock); // RAII风格的加锁  -- 对象创建自动加锁
            // pthread_mutex_lock(td->_lock);
            if (tickets > 0)
            {
                usleep(1);
                std::cout << name << " 我正在抢票 : " << tickets-- << std::endl;
                // std::cout << td->_name << " 我正在抢票 : " << tickets-- << std::endl;
                // pthread_mutex_unlock(&lock);
                // pthread_mutex_unlock(td->_lock);
            }
            else
            {
                // pthread_mutex_unlock(&lock);
                // pthread_mutex_unlock(td->_lock);
                break;
            }
            // 出了作用域自动解锁
        }

        // 抢了票就完了吗？ 不是
        usleep(1234); // 假设生成订单的时间
    }

    return nullptr;
}

int main()
{
    pthread_t t1, t2, t3, t4;
    pthread_create(&t1, nullptr, get_tickets, (void *)"user - 1");
    pthread_create(&t2, nullptr, get_tickets, (void *)"user - 2");
    pthread_create(&t3, nullptr, get_tickets, (void *)"user - 3");
    pthread_create(&t4, nullptr, get_tickets, (void *)"user - 4");

    pthread_join(t1, nullptr);
    pthread_join(t2, nullptr);
    pthread_join(t3, nullptr);
    pthread_join(t4, nullptr);

    //  #define NUM 4

    //     pthread_mutex_t lock;   // 定义局部的锁，需要进行下方的初始化
    //     pthread_mutex_init(&lock, nullptr);
    //     std::vector<pthread_t> tids(NUM);

    //     for(int i = 0; i < NUM; i++)
    //     {
    //         char namebuffer[64];
    //         snprintf(namebuffer, sizeof(namebuffer), "thread-%d", i + 1);
    //         ThreadData *td = new ThreadData(namebuffer, &lock);
    //         pthread_create(&tids[i], nullptr, get_tickets, td);
    //     }

    //     for(const auto& tid : tids)
    //     {
    //         pthread_join(tid, nullptr);
    //     }

    //     pthread_mutex_destroy(&lock);

    // std::unique_ptr<Thread> t1(new Thread(get_tickets, (void*)"user1", 1));
    // std::unique_ptr<Thread> t2(new Thread(get_tickets, (void*)"user2", 2));
    // std::unique_ptr<Thread> t3(new Thread(get_tickets, (void*)"user3", 3));
    // std::unique_ptr<Thread> t4(new Thread(get_tickets, (void*)"user4", 4));

    // t1->join();
    // t2->join();
    // t3->join();
    // t4->join();

    return 0;
}
